package main
import (
	"math"
	"fmt"
	"os"
	"errors"
)
/*

 basic  2 http://www.jb51.net/article/56726.htm
 basic  3 http://www.jb51.net/article/56768.htm
方法和接口,本文同时讲解了错误、匿名域等内容
 */

func main() {
	v := Vertex{3, 4}
	fmt.Println(v.Abs())


	// 成功，能够持有 *Vertex 类型的值
	var a Abser = &v
	fmt.Println(a)

	// 出错，不能持有 Vertex 类型的值
	// 因为在 *Vertex 上定义了方法 Abs，而未在 Vertex 上定义
	/*var b Abser = v
	fmt.Println(b)*/


	//2.1 error
	_,err:=os.Open("d:\\oauth2.sql")
	if err!=nil {
		 fmt.Println(err)
	}else {
		fmt.Println("no nil")
	}

	//2.2 error
	_,err2:=Sqrt(-1)
	if err2!=nil {
		fmt.Println(err2)
	}else {
		fmt.Println("no nil 2")
	}

	f := Ferrari{Car{4}}
	fmt.Println("A Ferrari has this many wheels: ", f.numberOfWheels())

}
/*在这里方法的接收者使用指针类型而非值类型主要出于以下几点考虑（类似 C/C++ 等语言）：
1.避免方法每次调用时，对接收者的不必要的拷贝
2.在方法内可以修改接收者的值
我们可以为任意类型定义方法，但以下情况除外：
1.如果类型定义在其他包中，不能为其定义方法
2.如果类型是基础类型，不能为其定义方法*/
//为结构体定义方法
//1 定义结构体
type Vertex struct {
	X, Y float64
}
//2 结构体 Vertex 的方法
// 这里的方法接收者（method receiver）v 的类型为 *Vertex
func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}


// 定义接口 Abser
type Abser interface {
	Abs() float64
}



func Sqrt(f float64) (float64, error) {
	if f < 0 {
		// 出错时返回一个错误
		return 0, errors.New("not allows param < 0")
	}
	return  f,nil
}

//定义一个新的error 类型
type NegativeSqrtError float64

func (f NegativeSqrtError) Error() string {
	return fmt.Sprintf("math: square root of negative number %g", float64(f))
}


// 匿名域

type Car struct {
	wheelCount int
}

func (car *Car) numberOfWheels() int {
	return car.wheelCount
}

type Ferrari struct {
	Car
}


